package com.jungle.bfi.service.metadata.impl;

import com.jungle.base.domain.bo.BaseUserBo;
import com.jungle.bfi.domain.bo.ApiMetadataBo;
import com.jungle.bfi.domain.bo.ApiPathBo;
import com.jungle.bfi.domain.bo.ApiUrlBo;
import com.jungle.bfi.entity.ApiPathPo;
import com.jungle.bfi.entity.ApiUrlPo;
import com.jungle.bfi.metadata.swagger.SwaggerReader;
import com.jungle.bfi.metadata.swagger.enums.PathType;
import com.jungle.bfi.metadata.swagger.vo.ApiPath;
import com.jungle.bfi.metadata.swagger.vo.SchemaInfo;
import com.jungle.bfi.service.metadata.ApiMetadataService;
import com.jungle.bfi.service.metadata.ApiParsingService;
import com.jungle.bfi.service.metadata.ApiPathService;
import com.jungle.bfi.service.metadata.ApiUrlService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import java.util.function.Function;

@Slf4j
@Service
public class ApiParsingServiceSwaggerImpl implements ApiParsingService {
    @Resource
    private ApiUrlService apiUrlService;
    @Resource
    private ApiPathService apiPathService;
    @Resource
    private ApiMetadataService apiMetadataService;

    @Override
    public void analyse(String apiUrl) {

        ApiUrlBo apiUrlBo = new ApiUrlBo();

        apiUrlBo.setApiUrl(apiUrl);
        // 保存apiUrl信息
        ApiUrlPo apiUrlPo = apiUrlService.saveOrUpdate(apiUrlBo, new BaseUserBo());

        String apiId = apiUrlPo.getId();
        // paths
        new SwaggerReader().read(apiUrl, apiPathConsumer(apiId), apiMetadataConsumer(apiId));
    }

    private Consumer<ApiPath> apiPathConsumer(String apiId) {
        AtomicReference<String> systemId = new AtomicReference<>();

        Map<String, String> moduleMap = new HashMap<>();

        return apiPath -> {
            if (PathType.SYSTEM.equals(apiPath.getType())) {
                // 系统路径
                ApiPathBo apiPathBo = toApiSystemPathPo(apiId).apply(apiPath);

                log.info("system info:{}", apiPathBo);
                ApiPathPo pathPo = apiPathService.saveOrUpdate(apiPathBo, new BaseUserBo());
                systemId.set(pathPo.getId());
            } else if (PathType.MODULE.equals(apiPath.getType())) {
                // 模块路径
                ApiPathBo apiPathBo = toApiModulePathPo(apiId).apply(apiPath);
                apiPathBo.setParentId(systemId.get());
                log.info("module info:{}", apiPathBo);
                ApiPathPo pathPo = apiPathService.saveOrUpdate(apiPathBo, new BaseUserBo());
                moduleMap.put(pathPo.getTitle(), pathPo.getId());
            } else if (PathType.FUNCTION.equals(apiPath.getType())){
                ApiPathBo apiPathBo = toApiPathPo(apiId).apply(apiPath);
                // 功能接口路径
                log.info("path info:{}", apiPathBo);
                apiPathBo.setParentId(moduleMap.get(apiPath.getTags().get(0)));
                apiPathService.saveOrUpdate(apiPathBo, new BaseUserBo());
            } else {
                log.info("unknown path type:{}", apiPath.getType());
            }
        };
    }

    private Consumer<List<SchemaInfo>> apiMetadataConsumer(String apiId) {
        return list -> list.forEach(schemaInfo -> {
            log.info("schema:{}", schemaInfo);
            ApiMetadataBo metadataBo = toApiMetadataBo(apiId).apply(schemaInfo);
            apiMetadataService.saveOrUpdate(metadataBo, new BaseUserBo());
        });
    }

    private Function<ApiPath, ApiPathBo> toApiSystemPathPo(String apiId) {
        return apiPath -> {
            ApiPathBo bo2 = new ApiPathBo();
            bo2.setApiId(apiId);
            bo2.setType(apiPath.getType().name());
            bo2.setPath(apiPath.getPath());
            bo2.setTitle(apiPath.getSummary());
            bo2.setDescription(apiPath.getDescription());

            return bo2;
        };
    }

    private Function<ApiPath, ApiPathBo> toApiModulePathPo(String apiId) {
        return apiPath -> {
            ApiPathBo bo2 = new ApiPathBo();
            bo2.setApiId(apiId);
            bo2.setType(apiPath.getType().name());
            bo2.setTitle(apiPath.getSummary());
            bo2.setPath(apiPath.getPath());
            return bo2;
        };
    }

    private Function<ApiPath, ApiPathBo> toApiPathPo(String apiId) {
        return apiPath -> {
            ApiPathBo bo2 = new ApiPathBo();
            bo2.setApiId(apiId);
            bo2.setType(apiPath.getType().name());
            bo2.setTitle(apiPath.getSummary());
            bo2.setPath(apiPath.getPath());
            bo2.setMethod(apiPath.getMethod());

            bo2.setTags(apiPath.getTags());
            bo2.setContentType(apiPath.getContentType());
            bo2.setSchemaType(apiPath.getSchemaType());
            bo2.setSchemaRef(apiPath.getSchemaRef());
            bo2.setDescription(apiPath.getDescription());
            return bo2;
        };
    }

    private Function<SchemaInfo, ApiMetadataBo> toApiMetadataBo(String apiId) {
        return info -> {
            ApiMetadataBo bo = new ApiMetadataBo();

            bo.setApiId(apiId);
            bo.setParentPath(String.join(".", info.getPaths()));
            bo.setOwnPath(bo.getParentPath().concat(".").concat(info.getName()));
            bo.setName(info.getName());
            bo.setTitle(info.getTitle());
            bo.setOriginType(info.getOriginType());
            bo.setType(info.getType());
            bo.setFormat(info.getFormat());
            bo.setDescription(info.getDescription());
            bo.setMaximum(info.getMaximum());
            bo.setMinimum(info.getMinimum());
            bo.setRef(info.getRef());

            return bo;
        };
    }
}
